package com.github.livebase.log;

import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

import com.github.livebase.util.base.CollectionsUtil;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * @ClassName LogFactory
 * @description:
 * @author: biao532
 * @create: 2024-02-02 21:07
 * @Version 1.0
 **/
public class LoggerFactory {
    public static final String LOGGER_DEFINITION_FILE_PATH = "";
    private static Map<String, Logger> loggers;

    static {
        /*List<LoggerDefinition> loggerDefinitions = LoggerDefinitionUtil.readFromXml(new File(LOGGER_DEFINITION_FILE_PATH));
        registerLoggers(loggerDefinitions);*/
    }

    public static Logger getLogger(Class clazz) {
        String packageName = "";
        if (clazz != null) {
            packageName = clazz.getName();
        }
        Logger log = maxMatch(packageName);
        if (null == log) {
            return ConsoleLogger.getLogger();
        }
        return log;
    }
    public static void registerLoggers(List<LoggerDefinition> definitions) {
        if (CollectionsUtil.isEmpty(definitions)) {
            return;
        }
        if (loggers == null) {
            loggers = new ArrayMap<>(definitions.size());
        }
        CollectionsUtil.foreach(definitions, (definition -> {
            try {
                LoggerFactory.registerLogger(definition);
            } catch (LoggerException e) {
                LoggerFactory.getLogger(LoggerFactory.class).warn("LoggerFactory", e);
            }
        }));
    }
    public static Logger registerLogger(LoggerDefinition definition) throws LoggerException {
        if (loggers != null && loggers.containsKey(definition.getPackageName())) {
            return null;
        }
        if (loggers == null) {
            loggers = new ArrayMap<>(10);
        }
        Logger l = createLogger(definition);
        if (l != null) {
            loggers.put(definition.getPackageName(), l);
            return l;
        }
        return null;
    }
    private static Logger maxMatch(String packageName) {
        Log.i("LoggerFactory", String.format("maxMatch(%s) loggers=%s", packageName, loggers));
        if (loggers == null) {
            throw new RuntimeException();
            //return null;
        }
        int maxMatch = -1;

        String target = null;
        for (String key : loggers.keySet()) {
            int l = belong(key, packageName);
            if (maxMatch < l) {
                maxMatch = l;
                target = key;
            }
        }
        if (target == null) {
            return null;
        }
        return loggers.get(target);
    }
    private static int belong(String parent, String children) {
        if (TextUtils.isEmpty(parent)) {
            return 0;
        }
        // parent的长度必然小于等于children的长度
        if (parent.length() > children.length()) {
            return -1;
        }
        if (!children.startsWith(parent)) {
            return -1;
        }
        if (parent.length() == children.length()) {
            return parent.length();
        }
        if (children.charAt(parent.length()) == '.') {
            return parent.length();
        }
        return -1;
    }
    private static String method(String varName) {
        char f = varName.charAt(0);
        if (f >= 'a' && f <= 'z') {
            f = (char) (f - 'a' + 'A');
        }
        return "set" + f + varName.substring(1);
    }

    private static void invoke(LoggerDefinition.Parameter parameter, Object target, Class clazz) throws LoggerException {
        String setMethodName = method(parameter.parameter);
        try {
            Method method = clazz.getMethod(setMethodName, parameter.clazz);
            method.invoke(target, parameter.value);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            throw new LoggerException(
                    String.format("an error occurred during invoke method[%s]", setMethodName), e);
        }
    }
    private static Logger createLogger(LoggerDefinition definition) throws LoggerException {
        try {
            Class clazz = LoggerFactory.class.getClassLoader().loadClass(definition.getClassName());
            if (!Logger.class.isAssignableFrom(clazz)) {
                return null;
            }
            Object obj = clazz.newInstance();
            for (LoggerDefinition.Parameter parameter : definition.getParams()) {
                invoke(parameter, obj, clazz);
            }
            return (Logger) obj;
        }
        catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            throw new LoggerException("an error occurred during createLogger for " + definition, e);
        }
    }
}
